package cn.mw.cmdb.service.impl;

import cn.mw.cmdb.param.SearchParamConvert;
import cn.mw.cmdb.service.ModelService;
import cn.mw.components.mongodb.mapper.BaseMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

import static cn.mw.cmdb.service.impl.CmdbServiceManage.operateLogRecordErrorMethod;

/*
 * 通过使用抽象方法调用子类, 实现各个服务生命周期的事件处理
 * T 表示单个操作的对象类型, B表示批量删除对象类型
 */
@Slf4j
public abstract class ModelBaseServiceImpl<T, B> extends BaseSearchService<T> implements ModelService<T, B> {

    @Override
    public Object add(T param) throws Exception {
        try {
            doAdd(param);
        } catch (Exception e) {
            if (e.getStackTrace() != null && e.getStackTrace().length > 0 && e.getStackTrace()[0] != null) {
                StackTraceElement stackTraceElement = e.getStackTrace()[0];
                log.error("begin deal with operateLogRecordErrorMethod::", e);
                operateLogRecordErrorMethod(param, stackTraceElement);
                throw e;
            }
        }
        return null;
    }

    @Override
    public boolean update(T param) throws Exception {
        doUpdate(param);
        return true;
    }

    @Override
    public boolean remove(T param) throws Exception {
        return doRemove(param);
    }

    @Override
    public Object batchAdd(Object params) throws Exception {
        return doBatchAdd(params);
    }

    @Override
    public boolean batchUpdate(Object params) throws Exception {
        return doBatchUpdate(params);
    }

    @Override
    public T selectById(Object id) throws Exception {
        return doSelectById(id);
    }

    @Override
    public List<T> selectList(Object param) throws Exception {
        if (param instanceof SearchParamConvert) {
            ((SearchParamConvert) param).convert();
        }
        return doSelectList(param);
    }

    @Override
    public boolean batchRemove(B params) throws Exception {
        return doBatchRemove(params);
    }

    abstract Object doAdd(T param) throws Exception;

    abstract boolean doUpdate(T param) throws Exception;

    abstract boolean doRemove(T param) throws Exception;

    abstract Object doBatchAdd(Object params) throws Exception;

    abstract boolean doBatchUpdate(Object params) throws Exception;

    abstract T doSelectById(Object id) throws Exception;

    abstract List<T> doSelectList(Object param) throws Exception;

    abstract boolean doBatchRemove(B params) throws Exception;

    protected <T> void batchUpdateTemplate(BaseMapper mapper, List<T> params, Class<T> clazz, Consumer<BatchUpdateContext<T>> callback) throws Exception {
        List<Pair<Query, Update>> updateList = new ArrayList<>();
        //UNORDERED是异步执行，有错误跳过继续执行；ORDERED时有序执行，遇到错误终止
        BulkOperations operations = mapper.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz);
        for (T data : params) {
            BatchUpdateContext batchUpdateContext = new BatchUpdateContext();
            batchUpdateContext.setData(data);

            callback.accept(batchUpdateContext);
            // 添加查询条件
            if (null != batchUpdateContext.getUpdate()) {
                Query query = batchUpdateContext.getQuery();
                Update update = batchUpdateContext.getUpdate();
                // 更新数据
                Pair<Query, Update> updatePair = Pair.of(query, update);
                updateList.add(updatePair);
            }
        }
        operations.updateMulti(updateList);
        operations.execute();
    }
}
